package com.xbaoziplus.simple_spring.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import com.xbaoziplus.simple_spring.beans.BeansException;
import com.xbaoziplus.simple_spring.beans.PropertyValue;
import com.xbaoziplus.simple_spring.beans.PropertyValues;
import com.xbaoziplus.simple_spring.beans.factory.config.BeanDefinition;
import com.xbaoziplus.simple_spring.beans.factory.config.BeanReference;

import java.lang.reflect.Constructor;

/**
 * @author xbaozi
 * @version 1.0
 * @classname AbstractAutowireCapableBeanFactory
 * @date 2023-04-18  17:40
 * @description 实现默认 bean 创建的抽象 bean 工厂父类，用于实现创建对象的具体功能
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
        Object bean = null;
        try {
            bean = createBeanInstance(beanDefinition, beanName, args);
            // 给 Bean 对象填充属性
            applyPropertyValue(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }
        registerSingleton(beanName, bean);
        return bean;
    }

    /**
     * @description 填充属性值
     * @author xbaozi
     * @date 2023/4/24 16:38
     * @param beanName  bean 名称
     * @param bean      bean 对象
     * @param beanDefinition    bean 定义
     **/
    protected void applyPropertyValue(String beanName, Object bean, BeanDefinition beanDefinition) {
        try {
            PropertyValues propertyValues = beanDefinition.getPropertyValues();
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
                String name = propertyValue.getName();
                Object value = propertyValue.getValue();

                if (value instanceof BeanReference) {
                    // 如果 A 依赖 B，获取 B 的实例化对象
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                // 属性填充
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (Exception e) {
            throw new BeansException("Error setting property values: " + beanName);
        }
    }

    /**
     * @param beanDefinition bean 定义
     * @param beanName       bean 名称
     * @param args           用显式参数创建 bean 实例时使用的参数
     * @return Object
     * @description 创建 bean 实例
     * @author xbaozi
     * @date 2023/4/20 20:46
     **/
    protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
        Constructor<?> constructorToUse = null;
        Class<?> beanClass = beanDefinition.getBeanClass();
        // 获取所有构造函数
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        for (Constructor<?> ctor : declaredConstructors) {
            // 判断构造函数是否合法
            if (null != args && ctor.getParameterTypes().length == args.length) {
                constructorToUse = ctor;
                break;
            }
        }
        // 实例化
        return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
    }

    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }
}
